
#include <QtGui/QInputDialog>

#include "mymainwindow.h"
#include "openglframe.h"
#include "../enumtypes.h"

#include <iostream>

using namespace std;

void printInfoAndExit() {
   
   cout<<endl;
   cout<<"Usage: CharAnim filename.{off | ply}"<<endl;
   cout<<"                [-skel skelname.skel]"<<endl;
   cout<<"                [-skin assocname.sb | attname.sj]"<<endl;
   exit(0);
}

/// Constructor.
MyMainWindow::MyMainWindow(QMainWindow *parent): QMainWindow(parent) 
{
   // Make sure the default opengl format includes stencil buffer and alpha.
   QGLFormat fmt;
   fmt.setAlpha(true);
   fmt.setStencil(true);
   QGLFormat::setDefaultFormat(fmt);
   
   // Executes the method which builds the remaining widgets of the window.
   // (Inherited from Ui::MainWindow)
   setupUi (this);
   
   //~ timer = new QTimer(this);
   
   connect(actionZoomIn, SIGNAL(triggered()), this->glFrame, SLOT(zoomIn()));
   connect(actionZoomOut, SIGNAL(triggered()), this->glFrame, SLOT(zoomOut()));
   connect(actionZoomAll, SIGNAL(triggered()), this->glFrame, SLOT(zoomAll()));
   
   // groupping exclusives actions 
   meshrenderGroup = new QActionGroup(this);
   meshrenderGroup->addAction(actionRenderPoints);
   meshrenderGroup->addAction(actionRenderWireframe);
   meshrenderGroup->addAction(actionRenderHiddenLines);
   meshrenderGroup->addAction(actionRenderFlatLines);
   meshrenderGroup->addAction(actionRenderFlat);
   meshrenderGroup->addAction(actionRenderTransparency);
   meshrenderGroup->addAction(actionRenderSmooth);
   
   meshRigSkinGroup = new QActionGroup(this);
   meshRigSkinGroup->addAction(actionViewRigging);
   meshRigSkinGroup->addAction(actionViewSkinning);
   meshRigSkinGroup->addAction(actionViewRiggingEdges);
   meshRigSkinGroup->addAction(actionNoViewRigSkin);
   
   // 
   viewVertexJointGroup = new QActionGroup(this);
   viewVertexJointGroup->addAction(actionVertexJoints);
   viewVertexJointGroup->addAction(actionVertexJoint);
   viewVertexJointGroup->addAction(actionJointVs);
   viewVertexJointGroup->addAction(actionJointV);
   connect(viewVertexJointGroup, SIGNAL(triggered(QAction *)), this, SLOT(viewVertexJointGroup_triggered(QAction *)));
   
   clusteringGroup = new QButtonGroup(this);
   clusteringGroup->addButton(rb_clustering_bones);
   clusteringGroup->addButton(rb_clustering_joints);
   
   kcenters = 0; // number of clusterings
   flag_skeleton = false;
}

void MyMainWindow::open(int argc, char *argv[]) {
   
   int carg = 2; // current argument
   int nargs = argc; // 
   //~ if (nargs < 6) printInfoAndExit();
   
   open_model(QString(argv[1]));
   while (carg < nargs) {
      QString currstring = argv[carg++];
      if(currstring == "-skel") {
         currstring = argv[carg++];
         open_skeleton(currstring);
         continue;
      }
      if(currstring == "-skin") {
         currstring = argv[carg++];
         open_skinning(currstring);
         continue;
      }
      cout<< "Unrecognized option: " <<currstring.toStdString()<<endl;
      printInfoAndExit();
   }
}

// Tries to load file if filename not empty.
void MyMainWindow::open_model(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      
      if (extension != "off") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < off > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->loadShapeOFF(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      filenamemodel = filename;
      this->setWindowTitle("Rigging/Skinning Interface - " + filenamemodel);
   }
}

void MyMainWindow::open_skeleton(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      
      if (extension != "skel") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < skel > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->loadSkeleton(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      else {
         // if every thing is ok
         flag_skeleton = true;
      }
   }
}

void MyMainWindow::open_skinning(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      if (extension != "sj" and extension != "sb") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < sb | sj > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->loadSkinning(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
   }
}

void MyMainWindow::on_actionOpen_model_triggered() 
{
    // Asks for a file name to open.
    QString filename = QFileDialog::getOpenFileName (
                      this, 
                      tr("Choose a mesh file"),
                      ".",
                      tr("Off meshes (*.off)"));
    
    // Tries to load file if filename not empty.
    if (filename != "") {
      open_model(filename);
      glFrame->updateGL();
    }
}

void MyMainWindow::on_actionOpen_skeleton_triggered() 
{
    // Asks for a file name to open.
    QString filename = QFileDialog::getOpenFileName (
                      this, 
                      tr("Choose a skeleton file"),
                      ".",
                      tr("Skel files (*.skel)"));
    
    // Tries to load file if filename not empty.
    if (filename != "") {
      glFrame->loadSkeleton(filename);
      glFrame->updateGL();
    }
}

void MyMainWindow::on_actionOpen_skinning_triggered() {
   
    // Asks for a file name to open.
    QString filename = QFileDialog::getOpenFileName (
                      this, 
                      tr("Choose a skinning file"),
                      ".",
                      tr("Skinning files (*.sb *.sj)"));
    
    // Tries to load file if filename not empty.
    if (filename != "") {
      glFrame->loadSkinning(filename);
      glFrame->updateGL();
    }
}

void MyMainWindow::on_actionSave_as_model_triggered() {
   
   // Asks for a file name to save
   QString filename = QFileDialog::getSaveFileName (
                this, 
                tr("Save model"),
                ".",
                tr("Off meshes (*.off)"));
    
   // Tries to save file if filename not empty.
   if (filename != "") {
      glFrame->saveAsSkeleton(filename);
   }
}

void MyMainWindow::on_actionSave_as_skeleton_triggered() {
   
   // Asks for a file name to save
   QString filename = QFileDialog::getSaveFileName (
                this, 
                tr("Save skeleton"),
                ".",
                tr("Skel files (*.skel)"));
    
   // Tries to save file if filename not empty.
   if (filename != "") {
      glFrame->saveAsSkeleton(filename);
   }
}

void MyMainWindow::on_actionSave_as_skinning_triggered() {
   
   if (rb_clustering_bones->isChecked()) {
      // Asks for a file name to save
      QString filename = QFileDialog::getSaveFileName (
                   this, 
                   tr("Save skinning"),
                   ".",
                   tr("Skinning_On_Bones files (*.sb)"));
      
      // Tries to save file if filename not empty.
      if (filename != "") {
         glFrame->saveSkinning(filename);
      }
   }
   else if (rb_clustering_joints->isChecked()) {
      QString filename = QFileDialog::getSaveFileName (
                   this, 
                   tr("Save skinning"),
                   ".",
                   tr("SkinningOnJoints files (*.sj)"));
      
      // Tries to save file if filename not empty.
      if (filename != "") {
         glFrame->saveSkinning(filename);
      }
   }
}

void MyMainWindow::on_rb_clustering_bones_toggled() {
   
   if (rb_clustering_bones->isChecked())
      glFrame->setClusterUsingBones(true);
}

void MyMainWindow::on_rb_clustering_joints_toggled() {
   
   if (rb_clustering_joints->isChecked())
      glFrame->setClusterUsingBones(false);
}

void MyMainWindow::on_actionRenderPoints_triggered() {
   glFrame->meshRenderMode(POINTS);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderWireframe_triggered() {
   glFrame->meshRenderMode(WIREFRAME);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderFlat_triggered() {
   glFrame->meshRenderMode(FLAT);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderFlatLines_triggered() {
   glFrame->meshRenderMode(FLATLINES);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderHiddenLines_triggered() {
   glFrame->meshRenderMode(HIDDENLINES);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderSmooth_triggered() {
   glFrame->meshRenderMode(SMOOTH);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderTransparency_triggered() {
   glFrame->meshRenderMode(TRANSPARENCY);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewRigging_triggered() {
   glFrame->meshRigSkinMode(RIGGING);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewSkinning_triggered() {
   glFrame->meshRigSkinMode(SKINNING);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewRiggingEdges_triggered() {
   glFrame->meshRigSkinMode(RIGGINGEDGES);
   glFrame->updateGL();
}

void MyMainWindow::on_actionNoViewRigSkin_triggered() {
   glFrame->meshRigSkinMode(NORIGSKIN);
   glFrame->updateGL();
}

void MyMainWindow::on_actionLightOnOff_triggered() {
   if (actionLightOnOff->isChecked())
      actionLightOnOff->setIcon(QIcon(QString::fromUtf8("icons/lighton.png")));
   else 
      actionLightOnOff->setIcon(QIcon(QString::fromUtf8("icons/lightoff.png")));
   glFrame->lightingOnOff(actionLightOnOff->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionProjection_triggered() {
   
   if (glFrame->isProjectionOrtho()) {
      const QString qstring("Perspective");
      actionProjection->setText(qstring);
      actionProjection->setIcon(QIcon(QString::fromUtf8("icons/perspective.png")));
      glFrame->orthographic(false);
   }
   else {
      const QString qstring("Orthographic");
      actionProjection->setText(qstring);
      actionProjection->setIcon(QIcon(QString::fromUtf8("icons/orthographic.png")));
      glFrame->orthographic(true);
   }
   
   glFrame->setGLview();
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewModel_triggered() {
   
   if (actionViewModel->isChecked())
      glFrame->viewItemOn(MODELDEF);
   else 
      glFrame->viewItemOff(MODELDEF);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewSkeleton_triggered() {
   
   if (actionViewSkeleton->isChecked())
      glFrame->viewItemOn(SKELETONDEF);
   else 
      glFrame->viewItemOff(SKELETONDEF);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewFloor_triggered() {
   
   if (actionViewFloor->isChecked())
      glFrame->viewItemOn(FLOOR);
   else 
      glFrame->viewItemOff(FLOOR);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewInfo_triggered() {
   
   if (actionViewInfo->isChecked())
      glFrame->viewItemOn(INFO);
   else 
      glFrame->viewItemOff(INFO);
   glFrame->updateGL();
}

void MyMainWindow::on_actionEditSkeleton_triggered() {
   
   if (actionEditSkeleton->isChecked())
      glFrame->setInteractionMode(EDITSKEL_MODE);
   else 
      glFrame->setInteractionMode(SELECT_MODE);
   glFrame->updateGL();
}

void MyMainWindow::on_actionSkinning_triggered() {
   
   glFrame->bindSkeleton();
   glFrame->updateGL();
}

void MyMainWindow::on_actionRigging_triggered() {
   
   int nv = glFrame->nvertices();
   if (nv == 0) return;
      
   if (flag_skeleton) {
      glFrame->meshClustering(rb_clustering_bones->isChecked());
   }
   else {
      bool ok;
      kcenters = QInputDialog::getInteger(this, tr("Enter the kcenter number"),
                                         tr("Number of kcenters:"), kcenters+1, 0, nv, 1, &ok);
      if (ok) {
         glFrame->meshClustering(kcenters);
      } else {
         // user pressed Cancel
      }
   }
   
   glFrame->updateGL();
}

void MyMainWindow::on_actionCreateSkeleton_triggered() {
   
   cout<<"on_actionCreateSkeleton_triggered..."<<endl;
   cout<<"to do ..."<<endl;
}

void MyMainWindow::on_actionViewClusters_triggered() {
   
   glFrame->setIsViewClusters(actionViewClusters->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionClosestJoint_triggered() {
   
   glFrame->viewClosestJoint(actionClosestJoint->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionAssociations_triggered() {
   
   glFrame->viewAssociations(actionAssociations->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionVertexJoints_changed() {
   
   glFrame->setIsViewVertexJoints(actionVertexJoints->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionVertexJoint_changed() {
   
   glFrame->setIsViewVertexJoint(actionVertexJoint->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionJointVs_changed() {
   
   glFrame->setIsViewJointVertices(actionJointVs->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionJointV_changed() {
   
   glFrame->setIsViewJointVertice(actionJointV->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::viewVertexJointGroup_triggered(QAction *a) {
   
}

void MyMainWindow::on_spinDifussionAmplitude_valueChanged() {
   
   glFrame->setSkinningDifussionAmplitude(spinDifussionAmplitude->value());
   glFrame->updateGL();
}

void MyMainWindow::on_spinNumberIterations_valueChanged() {
   
   glFrame->setSkinningNumberIterations(spinNumberIterations->value());
   glFrame->updateGL();
}

void MyMainWindow::on_spinNumberExpansions_valueChanged() {
   
   glFrame->setSkinningNumberExpansions(spinNumberExpansions->value());
   glFrame->updateGL();
}

void MyMainWindow::on_spinLapFilterAlpha_valueChanged() {
   
   glFrame->setLapFilterAlpha(spinLapFilterAlpha->value());
   glFrame->updateGL();
}
